#ifndef JSON_FOR_BERKELEY
#define JSON_FOR_BERKELEY
#include <stdio.h>
#include <stdlib.h>
#include "datastream.h"

#ifndef WHERE
#define WHERE fprintf(stderr,"[%s] %s:%d\n",__FILE__,__FUNCTION__,__LINE__)
#endif

/** different kind of json node */
enum json_node_type
	{
	json_node_integer=1,
	json_node_floating=2,
	json_node_boolean=3,
	json_node_null=4,
	json_node_string=5,
	json_node_array=6,
	json_node_object=7
	};

/** forward declaration */
struct JSONNode_t;

typedef long json_integer_t;
#define JSON_INTEGER_FMT "%ld"
typedef double json_floating_t;
#define JSON_FLOATING_FMT "%f"


/** an entry (key/value) for the json-object, used as a simple Linked list */
typedef struct JSONObjetEntry_t
	{
	struct JSONNode_t* key;
	struct JSONNode_t* value;
	struct JSONObjetEntry_t* next;
	}JSONObjetEntry,*JSONObjetEntryPtr;
/** free the entry (key/value) of a json-object */
extern void JSONObjetEntryFree(JSONObjetEntryPtr);
/** free the entry (key/value) of a json-object */
extern JSONObjetEntryPtr JSONObjetEntryNew(struct JSONNode_t* key,struct JSONNode_t* value);

/** A JSON node holding the different kind of JSON types (string, array, object ...) */
typedef struct JSONNode_t
	{
	/** a value from json_node_type */
	int type;
	/** a union defined by the 'type' field */
	union	{
		json_integer_t integer;
		json_floating_t floating;
		char boolean;
		/** O ended string */
		char* string;
		/** a json array  */
		struct {
		        /** array of items */
			struct JSONNode_t** items;
			/** number of items */
			int size;
			} array;
		/** a json object is a linked list of entries */
		struct {
			JSONObjetEntryPtr entry;
			} object;
		} value;
	}JSONNode,*JSONNodePtr;

/** free a node and its children */
extern void JSONNodeFree(JSONNodePtr);

/** returns a new null-json node */
extern JSONNodePtr JSONNodeNewNull();
/** returns a new json-integer node */
extern JSONNodePtr JSONNodeNewInteger(json_integer_t value);
/** returns a new json-floating number node */
extern JSONNodePtr JSONNodeNewFloating(json_floating_t value);
/** returns a new json-boolean number node */
extern JSONNodePtr JSONNodeNewBoolean(char value);
/** returns a new json-string , the string will be copied an released internaly */
extern JSONNodePtr JSONNodeNewString(const char* s);
/** returns a new json-string the string will be copied an released internaly */
extern JSONNodePtr JSONNodeNewNString(const char* s,int length);

/** creates a new json object */
extern JSONNodePtr JSONNodeObjectNew();
/** appends an entry (key,value) to a node-object, returns 1 on success, 0 on failure */
extern int JSONNodeObjectPut(JSONNodePtr object,JSONObjetEntryPtr value);

/** creates a new array */
extern JSONNodePtr JSONNodeArrayNew();
/** appends an item to a node-array, returns 1 on success, 0 on failure */
extern int JSONNodeArrayAppend(JSONNodePtr array,JSONNodePtr item);
/** returns the number of nodes in an array */
extern int JSONNodeArraySize(const JSONNodePtr array);
/** returns the index-th node in the node-array */
extern JSONNodePtr JSONNodeArrayAt(JSONNodePtr array,int index);
/** returns the length of the string, or the size of the array, or the number of entries or -1 */
int JSONNodeSize(const JSONNodePtr ptr);


/** prints the node and its children as json */
extern void JSONPrint(FILE* out,const JSONNodePtr ptr);

/** streams the node and its children as a binary stream */
extern DataStream JSONSerialize(const JSONNodePtr ptr);
/** creates a new JSON tree from a datastream binary stream */
extern JSONNodePtr JSONDeserialize(const DataStream);

/** parses the given string and returns a node or NULL if there was an error */
extern JSONNodePtr jsonParse(const char*);
/** parses the given file and returns a node or NULL is there was an error */
extern JSONNodePtr jsonParseFile(FILE*);

/** private structure used for parsing , most users should not use it */
typedef struct BisonContext_t
	{
	/** reference to my flex lexer */
	void* my_yyscanner;
	/** current string read by flex */
	void* flexbuff;
	/** input stream as string */
	char* input_string;
	/** string input length */
	int input_length;
	/** string input pos */
	int input_pos;
	/** input is a file */
	FILE* file_as_input;
	/** was there an error ? */
	int error_flag;
	/** node returned */
	JSONNodePtr node;
	/** error message NULL=no message */
	FILE* error_stream;
	}BisonContext,*BisonContextPtr;


#endif
